#pragma once

#include "liblegerber_global.h"

#include <QtGlobal>
#include <QList>
#include <QString>
#include <QStringList>

#include "gerber.h"
#include "aperturetemplate.h"

namespace LeGerber
{

	// TODO: QUndoCommand? Undo/Redo to analyse gerber command effects
	class Processor;

	class LEGERBER_EXPORT Command
	{
	public:
		Command();
		virtual ~Command();
		virtual void execute(Processor *processor);
		virtual int type() const { return -1; }
	};

	class LEGERBER_EXPORT NullCommand: public Command
	{
	public:
		NullCommand();

		enum
		{
			Type = 0
		};

		// Command interface
	public:
		virtual int type() const override { return Type; }

	};

	class LEGERBER_EXPORT SelectInterpolationCommand: public Command
	{
	public:
		explicit SelectInterpolationCommand(Interpolation interpolation = InvalidInterpolation);
		enum
		{
			Type = 1
		};


		Interpolation interpolation = InvalidInterpolation;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT InterpolateCommand: public Command
	{
	public:
		explicit InterpolateCommand(qreal x = qSNaN(), qreal y = qSNaN(), qreal i = qSNaN(), qreal j = qSNaN());
		enum
		{
			Type = 2
		};

		qreal xCoordinate;
		qreal yCoordinate;
		qreal xDistance;
		qreal yDistance;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT MoveCommand: public Command
	{
	public:
		explicit MoveCommand(qreal x = qSNaN(), qreal y = qSNaN());

		enum
		{
			Type = 3
		};

		qreal xCoordinate = qSNaN();
		qreal yCoordinate = qSNaN();

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT FlashCommand: public Command
	{
	public:
		explicit FlashCommand(qreal x = qSNaN(), qreal y = qSNaN());
		enum
		{
			Type = 4
		};

		qreal xCoordinate;
		qreal yCoordinate;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT SelectQuadrantCommand: public Command
	{
	public:
		explicit SelectQuadrantCommand(Quadrant quadrant);

		enum
		{
			Type = 5
		};

		Quadrant quadrant =InvalidQuadrant;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT BeginRegionCommand: public Command
	{
	public:
		enum
		{
			Type = 6
		};

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT EndRegionCommand: public Command
	{
	public:
		enum
		{
			Type = 7
		};

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT EndCommand: public Command
	{
	public:
		enum
		{
			Type = 8
		};

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT SelectUnitCommand: public Command
	{
	public:
		explicit SelectUnitCommand(Unit unit);

		enum
		{
			Type = 9
		};

		Unit unit = InvalidUnit;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT SelectPolarityCommand: public Command
	{
	public:
		explicit SelectPolarityCommand(Polarity polarity);

		enum
		{
			Type = 10
		};

		Polarity polarity = InvalidPolarity;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT SetApertureAttributeCommand: public Command
	{
	public:
		enum
		{
			Type = 11
		};

		QString name;
		QStringList values;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT ClearApertureAttributeCommand: public Command
	{
	public:
		enum
		{
			Type = 12
		};

		QString name;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT SetFileAttributeCommand: public Command
	{
	public:
		enum
		{
			Type = 13
		};

		QString name;
		QStringList values;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT AddApertureCommand: public Command
	{
	public:
		explicit AddApertureCommand(int number, const QString &templateName,
		                            const QList<qreal> &templateParameters);

		enum
		{
			Type = 14
		};

		int apertureNumber = 0;
		QString templateName;
		QList<qreal> parameters;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT SelectApertureCommand: public Command
	{
	public:
		explicit SelectApertureCommand(quint32 number);

		enum
		{
			Type = 15
		};
		quint32 apertureNumber = 0;

		QString number;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT CommentCommand: public Command
	{
	public:
		explicit CommentCommand(const QString &code, const QString &text);

		enum
		{
			Type = 16
		};

		QString code;
		QString text;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

	class LEGERBER_EXPORT SelectCoordinateNotationCommand: public Command
	{
	public:
		explicit SelectCoordinateNotationCommand(CoordinateNotation notation);

		enum
		{
			Type = 17
		};

		CoordinateNotation notation;

		// Command interface
	public:
		virtual int type() const override { return Type; }
	};

	class LEGERBER_EXPORT AddApertureTemplateCommand: public Command
	{
	public:
		explicit AddApertureTemplateCommand(const QString &templateName,
		                                    const QList<AperturePrimitive> &primitives);

		enum
		{
			Type = 18
		};

		QString templateName;
		QList<AperturePrimitive> primitives;

		// Command interface
	public:
		virtual int type() const override { return Type; }
		virtual void execute(Processor *processor) override;
	};

}